#include "../main.h"

#define BUFFSIZE 64 * 1024
KMap *key_map = NULL;

void read_cb(poll_event_t *poll_event, poll_event_element_t *node, struct epoll_event ev)
{
    char buf[BUFFSIZE] = {0};
    int msglength = read(node->fd, buf, BUFFSIZE);
    if (msglength > 0)
    {
        char bufcopy[msglength];
        memset(bufcopy, 0, msglength);
        memcpy(bufcopy, buf, msglength);
        appendData(ev.data.fd, bufcopy, msglength);
    }
}

void close_cb(poll_event_t *poll_event, poll_event_element_t *node, struct epoll_event ev)
{
    INFO_LOG("in close_cb");
    remove_by_key(key_map, node->fd);
    // close the socket, we are done with it
    poll_event_remove(poll_event, node->fd);
}

void accept_cb(poll_event_t *poll_event, poll_event_element_t *node, struct epoll_event ev)
{
    INFO_LOG("in accept_cb");
    // accept the connection
    struct sockaddr_in clt_addr;
    socklen_t clt_len = sizeof(clt_addr);
    int listenfd = accept(node->fd, (struct sockaddr *)&clt_addr, &clt_len);
    fcntl(listenfd, F_SETFL, O_NONBLOCK);
    fprintf(stderr, "got the socket %d\n", listenfd);

    if (key_map == NULL)
    {
        key_map = (KMap *)malloc(sizeof(KMap));
        key_map->head = NULL;
    }

    add_To_KMap(key_map, listenfd);

    // set flags to check
    uint32_t flags = EPOLLIN | EPOLLRDHUP | EPOLLHUP;
    poll_event_element_t *p;
    // add file descriptor to poll event
    poll_event_add(poll_event, listenfd, flags, &p);
    // set function callbacks
    p->read_callback = read_cb;
    p->close_callback = close_cb;
}

//time out function
int timeout_cb(poll_event_t *poll_event)
{
    // just keep a count
    if (!poll_event->data)
    {
        // no count initialised, then initialize it
        INFO_LOG("init timeout counter");
        poll_event->data = calloc(1, sizeof(int));
    }
    else
    {
        // increment and print the count
        int *value = (int *)poll_event->data;
        *value += 1;
        //LOG("time out number %d", *value);
        // printf("tick (%d)\n", *value);
    }
    return 0;
}
void *testServer()
{
    int port = 9002;
    //SIGPIPE handle by kernel
    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sigaction(SIGPIPE, &sa, 0);

    // create a TCP socket, bind and listen
    int sock = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in svr_addr;
    memset(&svr_addr, 0, sizeof(svr_addr));
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_addr.s_addr = htons(INADDR_ANY);
    svr_addr.sin_port = htons(port);
    set_reuseport(sock);
    int result = bind(sock, (struct sockaddr *)&svr_addr, sizeof(svr_addr));
    OUT_DEBUG(DEBUG, "bind port 9002 result:%d", result);
    get_rcv_BufSize(sock);
    set_rcv_BufSize(sock);
    // get_rcv_BufSize(sock);
    get_send_BufSize(sock);
    set_send_BufSize(sock);

    listen(sock, 10);
    set_fd_noblock(sock);
    fcntl(sock, F_SETFL, O_NONBLOCK);

    // create a poll event object, with time out of 1 sec
    poll_event_t *pe = poll_event_new(1000);
    // set timeout callback
    pe->timeout_callback = timeout_cb;
    poll_event_element_t *p;
    // add sock to poll event
    poll_event_add(pe, sock, EPOLLIN, &p);
    // set callbacks
    //p->read_callback = read_cb;
    p->accept_callback = accept_cb;
    p->close_callback = close_cb;
    // enable accept callback
    p->cb_flags |= ACCEPT_CB;
    // start the event loop
    use_the_force(pe);

    return 0;
}

int set_rcv_BufSize(int sockfd)
{
    int sockbuflen = 0;
    int len = sizeof(sockbuflen);
    sockbuflen = 2 * 1024 * 1024;
    setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void *)&sockbuflen, len);
    int ret = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void *)&sockbuflen, &len);
    if (ret < 0)
    {
        fprintf(stderr, "getsockopt error\n");
        return -1;
    }
    OUT_DEBUG(DEBUG, "set rcv buf size :%d", sockbuflen);
    return 0;
}

int get_rcv_BufSize(int sockfd)
{
    int ret = 0;
    int sockbuflen = 0;
    int len = sizeof(sockbuflen);
    ret = getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void *)&sockbuflen, &len);
    if (ret < 0)
    {
        fprintf(stderr, "getsockopt error\n");
        return -1;
    }
    OUT_DEBUG(DEBUG, "rcv buf: %d", sockbuflen);
    return 0;
}

int get_send_BufSize(int sockfd)
{
    int ret = 0;
    int sockbuflen = 0;
    int len = sizeof(sockbuflen);
    ret = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (void *)&sockbuflen, &len);
    if (ret < 0)
    {
        fprintf(stderr, "getsockopt error\n");
        return -1;
    }
    OUT_DEBUG(DEBUG, "get send buf size：%d", sockbuflen);
    return 0;
}

int set_send_BufSize(int sockfd)
{
    int sockbuflen = 0;
    int len = sizeof(sockbuflen);
    sockbuflen = 2 * 1024 * 1024;
    setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (void *)&sockbuflen, len);
    int ret = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (void *)&sockbuflen, &len);
    if (ret < 0)
    {
        fprintf(stderr, "getsockopt error\n");
        return -1;
    }
    OUT_DEBUG(DEBUG, "set send buf size :%d", sockbuflen);
    return 0;
}

void set_fd_noblock(int fd)
{
    int flag = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flag | O_NONBLOCK);
}

void set_reuseport(int sockfd)
{
    int opt = 1;
    // sockfd为需要端口复用的套接字
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const void *)&opt, sizeof(opt));
}